import React, { useRef } from "react";
import styles from "./index.less";
import cn from 'classnames';
import { Input, InputNumber, Button, Slider, message } from 'antd';
import { SettingOutlined, LockOutlined, CaretRightOutlined, CaretLeftOutlined, InfoCircleOutlined, DeleteOutlined } from '@ant-design/icons';
import FountainCode from "./FountainCode";
import FountainDecoder from './FountainDecoder';
import FountainCodeStore from "./FountainCodeStore";
import { useLocalObservable, observer } from "mobx-react-lite";
import { binaryToString } from "@/utils/common";

import icon_send_blue from '@/assets/images/icon_send_blue.png';
import icon_send_white from '@/assets/images/icon_send_white.png';
import icon_download_green from '@/assets/images/icon_download_green.png';
import icon_download_white from '@/assets/images/icon_download_white.png';
import icon_switch from '@/assets/images/icon_switch.png';

const { TextArea } = Input;

const fc = new FountainCode();
let decoder = new FountainDecoder(0, 0, 0);

const FountainCodePage: React.FC = observer(() => {
    const store = useLocalObservable(() => new FountainCodeStore());

    const simulationInterval = useRef<any>();

    // 点击编码
    const onEncodeClick = () => {
        if (!store.originDataBinary) {
            alert('请输入要编码的数据');
            return;
        }
        
        if (isNaN(store.blockSize) || store.blockSize <= 0) {
            alert('请输入有效的块大小');
            return;
        }

        const k = Math.ceil(store.originDataBinary.length / store.blockSize);
        const numEncodedBlocks = Math.floor(k * 2);

        decoder = new FountainDecoder(
            k,
            store.blockSize,
            store.originDataBinary.length
        );

        const encodedBlocks = fc.encode(
            store.originDataBinary,
            store.blockSize,
            numEncodedBlocks
        );
        console.log(`## k=${k}, encodedBlocks=${encodedBlocks.length}`);

        store.setPackageList(encodedBlocks);
        // 更新所需数据包数量
        store.setNeedCount(k);
                
        // 重置接收区域
        resetReceiver();
    }

    // 重置接收区域
    const resetReceiver = () => {
        // 重置已接收数据包
        store.setReceivedPackageList([]);
        
        // 重置模拟状态
        if (simulationInterval.current) {
            clearInterval(simulationInterval.current);
            simulationInterval.current = null;
        }
        store.setMocking(false);

        store.setDecodeResult('');
        
        // 重置统计
        store.setPackageSent(0);
        store.setPackageSuccess(0);
        store.setPackageLost(0);
    }

    // 随机发送
    const onRandomSendClick = () => {
        const { packageList, receivedPackageList } = store;
        if (packageList.length === 0) return;

        const noSendPackageList = packageList.filter(i => !receivedPackageList.find(j => j.index == i.index));
        
        if (noSendPackageList.length === 0) {
            alert('所有数据包已发送');
            return;
        }
        
        const randomIndex = Math.floor(Math.random() * noSendPackageList.length);
        const packet = noSendPackageList[randomIndex];
        
        // 模拟丢包
        const isLost = Math.random() * 100 < store.mockDropRate;
        
        if (isLost) {
            showPacketLoss(packet);
            store.setPackageLost(store.packageLost + 1);
        } else {
            sendPacket(packet);
            store.setPackageSuccess(store.packageSuccess + 1);
        }
        store.setPackageSent(store.packageSent + 1);
    }

    // 单个发送
    const onSingleSendClick = (packet: any) => {
        // 模拟丢包
        const isLost = Math.random() * 100 < store.mockDropRate;
        
        if (isLost) {
            showPacketLoss(packet);
            store.setPackageLost(store.packageLost + 1);
        } else {
            sendPacket(packet);
            store.setPackageSuccess(store.packageSuccess + 1);
        }
        store.setPackageSent(store.packageSent + 1);
    }

    // 开始暂停模拟
    const startStopMock = () => {
        const { packageList, receivedPackageList, mockDropRate, needCount } = store;

        if (simulationInterval.current) {
            // 停止模拟
            clearInterval(simulationInterval.current);
            simulationInterval.current = null;
            store.setMocking(false);
            return;
        }

        if (store.packageList.length === 0) {
            alert('请先编码数据');
            return;
        }

        // 重置统计
        store.setPackageSent(0);
        store.setPackageSuccess(0);
        store.setPackageLost(0);

        // 获取未发送的数据包
        const noSendPackageList = packageList.filter(i => !receivedPackageList.find(j => j.index == i.index));
        
        if (noSendPackageList.length === 0) {
            alert('所有数据包已发送');
            return;
        }

        store.setMocking(true);

        // 开始模拟
        let packetIndex = 0;
        simulationInterval.current = setInterval(() => {
            if (packetIndex >= noSendPackageList.length) {
                clearInterval(simulationInterval.current);
                simulationInterval.current = null;
                store.setMocking(false);
                return;
            }
            
            const packet = noSendPackageList[packetIndex];
            
            // 模拟丢包
            const isLost = Math.random() * 100 < mockDropRate;
            
            if (isLost) {
                showPacketLoss(packet);
                store.setPackageLost(store.packageLost + 1);
            } else {
                sendPacket(packet);
                store.setPackageSuccess(store.packageSuccess + 1);
            }
            store.setPackageSent(store.packageSent + 1);
            console.log(`## 成功=${store.packageSuccess}, 失败=${store.packageLost}, 需要=${needCount}, 已接收=${receivedPackageList.length}`);

            packetIndex++;
            // 如果所有必要的包都已接收，停止模拟
            if (receivedPackageList.length >= packageList.length) {
                clearInterval(simulationInterval.current);
                simulationInterval.current = null;
            }
        }, 100);
    }

    // 发送成功动画
    const sendPacket = (pac: any) => {
        // 接收并处理编码包（接收端逻辑）
        decoder.receivePacket(pac);

        const copy = [...store.receivedPackageList, pac];
        store.setReceivedPackageList(copy);

        animatePacket(pac, true);
    }

    // 发送失败动画
    const showPacketLoss = (pac: any) => {
        animatePacket(pac, false);
    }

    // 展示动画（成功或失败）
    const animatePacket = (pac: any, isSuccess: boolean) => {
        if (isSuccess) {
            message.success(`发送成功: ${pac.id}`);
        } else {
            message.error(`发送失败: ${pac.id}`);
        }
    }

    // 解码数据
    const onDecodeClick = () => {
        if (decoder.isFullyDecoded()) {
            console.log(`## isFullyDecoded=true`);
            try {
                const decodedData = decoder.getDecodedData();
                const decodedString = new TextDecoder().decode(
                    decodedData
                );
                store.setDecodeResult(binaryToString(decodedString));
                console.log(`GS 解码${decodedString === store.originDataBinary ? '成功' : '失败'}`);
                message.success('解码成功');
                return;
            } catch (error: any) {
                console.log("full 解码失败:", error.message);
                message.error(`解码失败: ${error.message || ''}`);
            }
        }
        console.log(`## isFullyDecoded=false`);

        // 如果尚未完全解码，尝试高斯消元法
        if (store.receivedPackageList.length >= store.needCount) {
            const success = decoder.tryGaussianElimination();
            console.log(`## tryGaussianElimination=${success}`);
            if (success) {
                // 验证解码结果
                try {
                    const decodedData = decoder.getDecodedData();
                    const decodedString = new TextDecoder().decode(
                        decodedData
                    );
                    store.setDecodeResult(binaryToString(decodedString));
                    console.log(`GS 解码${decodedString === store.originDataBinary ? '成功' : '失败'}`);
                    message.success('解码成功');
                } catch (error: any) {
                    console.log("GS 解码失败:", error.message);
                    message.error(`解码失败: ${error.message || ''}`);
                }
            }
        }
    }

    // 删除包
    const onDeleteClick = () => {
        resetReceiver();
    }

    const renderDesc = () => {
        return (
            <div className={styles.desc}>
                <p className={styles.title}>喷泉码简介</p>
                <p className={styles.subtitle}>
                    喷泉码是一种前向纠错码，特别适合于不可靠或广播式网络环境。与传统纠错码不同，喷泉码可以生成无限数量的编码包，接收方只需收集足够数量的包即可恢复原始数据。
                </p>
                <div className={styles.row}>
                    <div className={styles.item}>
                        <div className={styles.send}>
                            <img src={icon_send_blue} />
                            <span>发送端</span>
                        </div>

                        <p className={styles.tips}>
                            发送端将原始数据分成块，然后通过特定算法生成无限数量的编码包。每个编码包都包含足够的信息来恢复原始数据，只要收集到足够数量的包。
                        </p>
                    </div>

                    {/* <div style={{ width: 20 }} /> */}

                    <div className={styles.item}>
                        <div className={styles.receive}>
                            <img src={icon_download_green} />
                            <span>接收端</span>
                        </div>

                        <p className={styles.tips}>
                            接收端收集这些编码包，不需要知道具体需要多少个包。当收集到的包数量达到或超过原始数据块数量时，即可恢复原始数据。
                        </p>
                    </div>
                </div>
            </div>
        );
    }

    const renderDemo = () => {
        return (
            <>
            <p className={styles.title}>喷泉码演示</p>

            <div className={styles.row}>
                <div className={styles.item}>
                    <div className={styles.itemHeader} style={{ backgroundColor: 'rgb(59, 130, 246)' }}>
                        <img src={icon_send_white} />
                        <span>发送端</span>
                    </div>

                    <div className={styles.content}>
                        <p className={styles.label}>原始数据</p>
                        <TextArea
                            showCount
                            maxLength={10000}
                            onChange={(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
                                store.setOriginData(e.target.value);
                            }}
                            placeholder="请输入发送内容"
                            style={{ height: 160, resize: 'none', fontSize: 16, color: '#333' }}
                            value={store.originData}
                        />

                        <p className={styles.label}>块大小</p>
                        <InputNumber size="large" min={1} max={512} defaultValue={16} value={store.blockSize} addonBefore='字符数' style={{ width: '100%' }} onChange={(value) => {
                            store.setBlockSize(value || 1);
                        }} />

                        <div className={styles.buttonRow}>
                            <Button type="primary" icon={<SettingOutlined />} size={'large'} style={{ flex: 1, marginRight: 16 }} onClick={onEncodeClick}>
                                编码数据
                            </Button>

                            <Button type="primary" color='purple' variant="solid" size={'large'} style={{ width: 120 }} onClick={onRandomSendClick}>
                                 随机发送
                            </Button>
                        </div>

                        <p className={styles.label}>编码数据包</p>
                        <div className={styles.packagesLayout}>
                            {store.packageList.map((i, index) => {
                                return (
                                    <div className={styles.packageItem} key={`${index}`}>
                                        <span className={styles.name}>{`包 #${i.index}    `}</span>
                                        <span className={styles.du}>{`度: ${i.degree}`}</span>
                                        <div className={styles.sendButton} onClick={() => onSingleSendClick(i)}>
                                            <img src={icon_send_blue} />
                                            <span>发送</span>
                                        </div>
                                    </div>
                                );
                            })}
                        </div>
                    </div>
                </div>

                <div className={styles.item}>
                    <div className={styles.itemHeader} style={{ backgroundColor: 'rgb(16, 185, 129)' }}>
                        <img src={icon_download_white} />
                        <span>接收端</span>
                    </div>

                    <div className={styles.content}>
                        <p className={styles.label}>已接收数据包</p>
                        <div className={styles.packagesLayout}>
                            {store.receivedPackageList?.length ? store.receivedPackageList.map((i, index) => {
                                return (
                                    <div className={styles.receivedPackageItem} key={`${index}`}>
                                        <span className={styles.name}>{`包 #${i.index}    `}</span>
                                        <span className={styles.du}>{`度: ${i.degree}`}</span>
                                        <div className={styles.sendButton}>
                                            <span>已接收</span>
                                        </div>
                                    </div>
                                );
                            }) : (
                                <p style={{ fontSize: 18, color: '#666', marginTop: 36, width: '100%', textAlign: 'center' }}>
                                    <InfoCircleOutlined /> 等待接收数据包
                                </p>
                            )}
                        </div>

                        <p className={styles.label}>解码结果</p>
                        <TextArea
                            showCount
                            maxLength={10000}
                            disabled={true}
                            placeholder="解码结果显示在这里"
                            value={store.decodeResult}
                            style={{ height: 155, resize: 'none', fontSize: 16, color: '#333' }}
                        />

                        <div className={styles.buttonRow} style={{ marginTop: 30 }}>
                            <Button type="primary" icon={<LockOutlined />} size={'large'} disabled={!store.receivedPackageList?.length} style={{ flex: 1, marginRight: 16, backgroundColor: 'rgb(16, 185, 129)' }} onClick={onDecodeClick}>
                                解码数据
                            </Button>

                            <Button type="primary" icon={<DeleteOutlined />} color='purple' variant="solid" size={'large'} disabled={!store.receivedPackageList?.length} style={{ width: 120, color: '#333', backgroundColor: '#e0e0e0' }} onClick={onDeleteClick}>
                                删除包
                            </Button>
                        </div>

                        <div className={styles.infoRow}>
                            <div className={styles.infoItem}>
                                <span className={styles.infoLabel}>已接收数据包</span>
                                <span className={styles.receivedCount}>{store.receivedPackageList?.length || 0}</span>
                            </div>

                            <div className={styles.infoItem}>
                                <span className={styles.infoLabel}>需要的最少数据包</span>
                                <span className={styles.needCount}>{store.needCount || 0}</span>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            </>
        );
    }

    const renderTransfer = () => {
        return (
            <div className={styles.mockTransfer}>
                <div className={styles.itemHeader} style={{ backgroundColor: 'rgb(16, 185, 129)' }}>
                    <img src={icon_switch} />
                    <span>模拟传输</span>
                </div>

                <div className={styles.transferContent}>
                    <div className={styles.transferRow}>
                        <span>模拟丢包率</span>
                        <Slider
                            defaultValue={20}
                            max={90}
                            min={0}
                            value={store.mockDropRate}
                            style={{ width: 400, marginLeft: 12 }}
                            tooltip={{ open: true, formatter: (value) => `${value}%` }}
                            onChange={(value: number | number[]) => {
                                store.setMockDropRate(value as number);
                            }}
                        />
                        <div style={{ flex: 1 }} />
                        <Button type="primary" icon={store.mocking ? <CaretLeftOutlined /> : <CaretRightOutlined />} size={'large'} style={{ backgroundColor: 'purple' }} onClick={startStopMock}>
                            {store.mocking ? '暂停模拟' : '开始模拟'}
                        </Button>
                    </div>

                    <div className={styles.animLayout}>

                    </div>

                    <div className={styles.transferRow}>
                        <div className={cn(styles.transferItem, styles.success)}>
                            <span>传输成功</span>
                            <span>{store.packageSuccess}</span>
                        </div>

                        <div className={cn(styles.transferItem, styles.fail)}>
                            <span>丢包</span>
                            <span>{store.packageLost}</span>
                        </div>

                        <div className={cn(styles.transferItem, styles.percent)}>
                            <span>传输比例</span>
                            <span>{((store.packageSuccess * 100 / store.needCount) || 0).toFixed(0)}%</span>
                        </div>
                    </div>
                </div>
            </div>
        );
    }

    return (
        <div className={styles.container}>
            {renderDesc()}
            {renderDemo()}
            {renderTransfer()}
        </div>
    );
});

export default FountainCodePage;
